﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Data;
using System.Dynamic;
using System.Linq;
using System.Reflection;
using System.Text;

namespace DG.Common.Reflection
{
    public static class EnumerableExtensions
    {
        public static DataTable ToDataTable(this IEnumerable source, IEnumerable<PropertyInfo> props, bool convertEnumToString = false)
        {
            var projectList = source.Cast<object>().ToList();

            var types = new HashSet<Type>(projectList.Where(p => !Equals(p, null)).Select(p => p.GetType()));
            while (types.Count > 1)
            {
                types = new HashSet<Type>(types.Select(t => t.BaseType).Where(t => t != null));
            }

            var type = types.SingleOrDefault();

            var dt = new DataTable();

            if (type != null && projectList.Any())
            {
                dt.TableName = type.FullName;

                props = props.ToArray();

                foreach (var prop in props)
                {
                    var colType = prop.PropertyType;

                    if ((colType.IsGenericType) && (colType.GetGenericTypeDefinition() == typeof(Nullable<>)))
                    {
                        colType = colType.GetGenericArguments()[0];
                    }
                    var displayAtribute = (prop.GetCustomAttributes(true)).OfType<DisplayAttribute>().FirstOrDefault();

                    var name= displayAtribute == null ? prop.Name : displayAtribute.Name;

                    var column = dt.Columns.Add(name, (convertEnumToString && colType.IsEnum) ? typeof(string) : colType);
                }

                foreach (var item in projectList)
                {
                    var closureItem = item;
                    dt.Rows.Add(props.Select(p =>
                    {
                        var val = p.GetValue(closureItem, null);
                        if (convertEnumToString && p.PropertyType.IsEnum) return val + "";
                        return val;
                    }).ToArray());
                }
            }

            return dt;
        }
        public static DataTable ToPrimitiveDataTable(this IEnumerable source)
        {
            
            var projectList = source.Cast<object>().ToList();

            var types = new HashSet<Type>(projectList.Where(p=> !Equals(p, null)).Select(p => p.GetType()));
            while (types.Count > 1)
            {
                types = new HashSet<Type>(types.Select(t => t.BaseType).Where(t=> t != null));
            }

            var type = types.SingleOrDefault();

            var dt = new DataTable();

            if (type != null && projectList.Any())
            {
                dt.TableName = type.FullName;

                var notPrimitiveAllowedTypes = new[] { typeof(string),typeof(Guid), typeof(DateTime), typeof(decimal), typeof(TimeSpan) };

                var props = type.GetProperties().Where(p =>
                        p.PropertyType.IsPrimitive
                        || notPrimitiveAllowedTypes.Contains(p.PropertyType)
                        || (p.PropertyType.IsGenericType && p.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
                        ).ToArray();
                dt = ToDataTable(projectList, props);
            }

            return dt;

        }
        
    }
}
